#ifndef ____BLOCKQUEUE_HPP____
#define ____BLOCKQUEUE_HPP____

#include <iostream>
#include <queue>
#include <pthread.h>
#include <string>
#include <unistd.h>
#include "Task.hpp"
#include "Cond.hpp"
#include "mutex.hpp"
const int Capacity = 5;

template <class T>
class BlockQueue
{
private:
    bool empty()
    {
        return _bq.empty();
    }

    bool full()
    {
        return _bq.size() == _cap;
    }

public:
    BlockQueue(int cap = Capacity)
        : _cap(cap)
    {
    }

    ~BlockQueue()
    {
    }

    void push(const T &_data)
    {
        {
            Mutex::AutoLock lock(_lock);
            while (full())
            {
                _p_wait++;
                _p_cond.Wait(_lock);
                _p_wait--;
            }

            _bq.push(_data);
            if (_c_wait > 0)
                _c_cond.Signal();
        }
    }

    T pop()
    {
        T data = T();
        {
            Mutex::AutoLock lock(_lock);
            while (empty())
            {
                _c_wait++;
                _c_cond.Wait(_lock);
                _c_wait--;
            }

            T _data = _bq.front();
            data = _data;
            _bq.pop();
            if (_p_wait > 0)
                _p_cond.Signal();
        }

        return data;
    }

private:
    std::queue<T> _bq;

    size_t _cap;
    Mutex::mutex _lock;
    Cond _c_cond;
    Cond _p_cond;
    size_t _c_wait = 0;
    size_t _p_wait = 0;
};

struct data
{
    BlockQueue<Task> *_bq;
    std::string _name;
};

#endif
